﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Web;

namespace NLBS.Urls
{
    /// <summary>
    /// Represents a particular directory
    /// </summary>
    public class Location : IEnumerable
    {
        private List<ReWrittenUrl> _urls = new List<ReWrittenUrl>();

        /// <summary>
        /// ReWrittenUrls within this Location
        /// </summary>
        public List<ReWrittenUrl> Urls
        {
            get { return _urls; }
        }

        /// <summary>
        /// Adds a ReWrittenUrl to this Location
        /// </summary>
        /// <param name="url">ReWrittenUrl to add to this Location</param>
        public void Add(ReWrittenUrl url)
        {
            _urls.Add(url);
        }

        /// <summary>
        /// The count of ReWrittenUrls within this Location
        /// </summary>
        public int Count
        {
            get { return _urls.Count; }
        }

        /// <summary>
        /// Returns an enumerator that iterates through the ReWrittenUrls in this Location
        /// </summary>
        /// <returns></returns>
        public IEnumerator GetEnumerator()
        {
            return _urls.GetEnumerator();
        }

        /// <summary>
        /// Instantiates a new Location
        /// </summary>
        /// <param name="path">Url path to this location</param>
        /// <param name="physicalPath">Physical Url path to this location (if null, path is used)</param>
        /// <param name="themeDir">Url path to the root folder of themes to be used in this location</param>
        /// <param name="exclude">Defines whether this location should be excluded from Url rewriting</param>
        public Location(string path, string physicalPath, string themeDir, bool exclude)
        {
            _path = path;
            if (physicalPath == null)
                _physicalPath = path;
            else
                _physicalPath = physicalPath;

            _exclude = exclude;
            _themeDir = themeDir;

            if (!string.IsNullOrEmpty(path))
            {
                _regex = new Regex("^" + path, RegexOptions.IgnoreCase | RegexOptions.Compiled);
            }
        }


        private Regex _regex = null;
        private string _path;
        private string _physicalPath;
        private string _themeDir = null;
        private bool _exclude = false;

        /// <summary>
        /// Url path to the root folder of themes to be used in this location
        /// </summary>
        public virtual string ThemeDirectory
        {
            get { return _themeDir; }
        }

        /// <summary>
        /// Defines whether this location should be excluded from Url rewriting
        /// </summary>
        public bool Exclude
        {
            get { return _exclude; }
        }

        /// <summary>
        /// Returns true if the Url path matches this location
        /// </summary>
        /// <param name="url">Url path to test</param>
        /// <returns>True if the Url matches this location</returns>
        public bool IsMatch(string url)
        {
            if (_regex == null)
                return false;
            bool a = _regex.IsMatch(url);
            return _regex.IsMatch(url);
        }

        /// <summary>
        /// Physical Url path to this location
        /// </summary>
        public string PhysicalPath
        {
            get
            {
                return _physicalPath;
            }
        }

        /// <summary>
        /// Url path to this location
        /// </summary>
        public string Path
        {
            get { return _path; }
        }

        /// <summary>
        /// Returns the ThemePage matching the ReWrittenUrl
        /// </summary>
        /// <param name="url">ReWrittenUrl for which to retrieve the ThemePage</param>
        /// <returns>The matching ThemePage or null if no ThemePage could be determined</returns>
        public virtual ThemePage ThemePage(ReWrittenUrl url)
        {
            ThemePage tp = new ThemePage();
            //tp.Name = HttpContext.;
            tp.Directory = this.ThemeDirectory;

            //return tp;

            return null;
        }

        /// <summary>
        /// Returns the rewritten Url for the specified ReWrittenUrl, original Url path, and query string
        /// </summary>
        /// <param name="url">ReWrittenUrl to rewrite</param>
        /// <param name="path">Original Url path to rewrite</param>
        /// <param name="queryString">Query string to rewrite</param>
        /// <returns>Rewritten url</returns>
        public virtual string GetReWrittenUrl(ReWrittenUrl url, string path, string queryString)
        {
            return url.GetReWrittenUrl(path, queryString, ThemePage(url));
        }

        private readonly static string matchKey = "ReWritteUrlMatchKey";

        /// <summary>
        /// Called when a matching ReWrittenUrl is found during processing of GetReWrittenUrl.  This method can be used to perform additional caching or processing of the matched ReWrittenUrl.
        /// </summary>
        /// <param name="context">HttpContext being processed</param>
        /// <param name="url">Matched ReWrittenUrl</param>
        /// <param name="newPath">New url</param>
        protected virtual void OnMatch(HttpContext context, ReWrittenUrl url, string newPath)
        {
            if (url.IsRedirect)
            {
                Uri newPathUri = new Uri(context.Request.Url, newPath);
                context.Response.RedirectLocation = newPathUri.ToString();
                context.Response.StatusCode = 301;
                context.Response.End();

            }

            context.Items[matchKey] = url.Name;
        }

        /// <summary>
        /// Returns the rewritten Url for the specified HttpContext, original Url path, and query string
        /// </summary>
        /// <param name="context">HttpContext being processed</param>
        /// <param name="path">Original Url path to rewrite</param>
        /// <param name="queryString">Query string to rewrite</param>
        /// <returns>Rewritten url</returns>
        public virtual string GetReWrittenUrl(HttpContext context, string path, string queryString)
        {
            string newPath = null;
            if (this.Count > 0)
            {
                foreach (ReWrittenUrl url in this)
                {
                    if (url.IsMatch(path))
                    {
                        newPath = GetReWrittenUrl(url, path, queryString);
                        OnMatch(context, url, newPath);
                        break;
                    }

                }
            }

            return newPath;
        }


        /// <summary>
        /// Returns the rewritten Url for the specified original Url path, and query string
        /// This method does not modify the current HttpContext and can be used for manual url parsing
        /// </summary>
        /// <param name="path">Original Url path to rewrite</param>
        /// <param name="queryString">Query string to rewrite</param>
        /// <returns>Rewritten url</returns>
        public virtual string GetReWrittenUrl(string path, string queryString)
        {
            string newPath = null;
            if (this.Count > 0)
            {
                foreach (ReWrittenUrl url in this)
                {
                    if (url.IsMatch(path))
                    {
                        newPath = GetReWrittenUrl(url, path, queryString);
                        break;
                    }

                }
            }

            return newPath;
        }

    }
}
